---
title: StateProvider
---

import CodeBlock from "@theme/CodeBlock";
import product from "!!raw-loader!/docs/providers/state_provider/product.dart";
import productListView from "!!raw-loader!/docs/providers/state_provider/product_list_view.dart";
import dropdown from "!!raw-loader!/docs/providers/state_provider/dropdown.dart";
import sortProvider from "!!raw-loader!/docs/providers/state_provider/sort_provider.dart";
import connectedDropdown from "!!raw-loader!/docs/providers/state_provider/connected_dropdown.dart";
import sortedProductProvider from "!!raw-loader!/docs/providers/state_provider/sorted_product_provider.dart";
import updateReadTwice from "!!raw-loader!/docs/providers/state_provider/update_read_twice.dart";
import updateReadOnce from "!!raw-loader!/docs/providers/state_provider/update_read_once.dart";
import { trimSnippet } from "../../../../../src/components/CodeSnippet";

:::caution
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
:::

`StateProvider` is a provider that exposes a way to modify its state.
It is a simplification of [NotifierProvider], designed to avoid
having to write a [Notifier] class for very simple use-cases.

`StateProvider` exists primarily to allow the modification of
**simple** variables by the User Interface.  
The state of a `StateProvider` is typically one of:

- an enum, such as a filter type
- a String, typically the raw content of a text field
- a boolean, for checkboxes
- a number, for pagination or age form fields

You should not use `StateProvider` if:

- your state needs validation logic
- your state is a complex object (such as a custom class, a list/map, ...)
- the logic for modifying your state is more advanced than a simple `count++`.

For more advanced cases, consider using [NotifierProvider] instead and
create a [Notifier] class.  
While the initial boilerplate will be a bit larger, having a custom
[Notifier] class is critical for the long-term maintainability of your
project – as it centralizes the business logic of your state in a single place.

## Usage example: Changing the filter type using a dropdown

A real-world use-case of `StateProvider` would be to manage the state of
simple form components like dropdowns/text fields/checkboxes.  
In particular, we will see how to use `StateProvider` to implement a dropdown
that allows changing how a list of products is sorted.

For the sake of simplicity, the list of products that we will obtain
will be built directly in the application and will be as follows:

<CodeBlock>{trimSnippet(product)}</CodeBlock>

In a real-world application, this list would typically be obtained using
[FutureProvider] by making a network request.

The User Interface could then show the list of products by doing:

<CodeBlock>{trimSnippet(productListView)}</CodeBlock>

Now that we're done with the base, we can add a dropdown, which will
allow filtering our products either by price or by name.  
For that, we will use [DropDownButton](https://api.flutter.dev/flutter/material/DropdownButton-class.html).

<CodeBlock>{trimSnippet(dropdown)}</CodeBlock>

Now that we have a dropdown, let's create a `StateProvider` and
synchronize the state of the dropdown with our provider.

First, let's create the `StateProvider`:

<CodeBlock>{trimSnippet(sortProvider)}</CodeBlock>

Then, we can connect this provider with our dropdown by doing:

<CodeBlock>{trimSnippet(connectedDropdown)}</CodeBlock>

With this, we should now be able to change the sort type.  
It has no impact on the list of products yet though! It's now time for the
final part: Updating our `productsProvider` to sort the list of products.

A key component of implementing this is to use [ref.watch], to have
our `productsProvider` obtain the sort type and recompute the list of
products whenever the sort type changes.

The implementation would be:

<CodeBlock>{trimSnippet(sortedProductProvider)}</CodeBlock>

That's all! This change is enough for the User Interface to automatically
re-render the list of products when the sort type changes.

Here is the complete example on Dartpad:

<iframe
  src="https://dartpad.dev/embed-flutter.html?gh_owner=rrousselGit&gh_repo=riverpod&gh_path=website%2Fdocs%2Fproviders%2Fstate_provider"
  style={{ border: 0, width: "100%", aspectRatio: "2/1.5" }}
></iframe>

## How to update the state based on the previous value without reading the provider twice

Sometimes, you want to update the state of a `StateProvider` based on the previous value.
Naturally, you may end-up writing:

<CodeBlock>{trimSnippet(updateReadTwice)}</CodeBlock>

While there's nothing particularly wrong with this snippet, the syntax is a bit inconvenient.

To make the syntax a bit better, we can use the `update` function.
This function will take a callback that will receive the current state and is expected
to return the new state.  
We can use it to refactor our previous code to:

<CodeBlock>{trimSnippet(updateReadOnce)}</CodeBlock>

This change achieves the same effect while making the syntax a bit better.

[ref.watch]: ../concepts/reading#using-refwatch-to-observe-a-provider
[ref.read]: ../concepts/reading#using-refread-to-obtain-the-state-of-a-provider-once
[statenotifierprovider]: ./state_notifier_provider
[notifierprovider]: ./notifier_provider
[futureprovider]: ./future_provider
[notifier]: https://pub.dev/documentation/riverpod/latest/riverpod/Notifier-class.html
[statenotifier]: https://pub.dev/documentation/state_notifier/latest/state_notifier/StateNotifier-class.html
[provider]: ./provider
[asyncvalue]: https://pub.dev/documentation/riverpod/latest/riverpod/AsyncValue-class.html
[future]: https://api.dart.dev/dart-async/Future-class.html
[family]: ../concepts/modifiers/family
